# -------------------------------------------------------------------------
#
#  Part of the CodeChecker project, under the Apache License v2.0 with
#  LLVM Exceptions. See LICENSE for license information.
#  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# -------------------------------------------------------------------------

import os
import json
import logging
from typing import Iterator, List, Tuple

from codechecker_report_converter.report import BugPathEvent, \
    get_or_create_file, Report

from ..parser import BaseParser

LOG = logging.getLogger('report-converter')


class Parser(BaseParser):
    """Parser for JSCPD json output."""

    def get_reports(self, file_path: str) -> List[Report]:
        """Parse JSCPD's json output file."""

        reports: List[Report] = []
        try:
            with open(file_path, 'r', encoding="utf-8", errors="ignore") as f:
                data = json.load(f)
        except (IOError, json.decoder.JSONDecodeError):
            LOG.error("Failed to parse the given analyzer result '%s'. Please "
                      "give a valid json file generated by jscpd.",
                      file_path)
            return reports

        if data:
            for duplication in data['duplicates']:
                report = self.get_report(duplication)
                reports.append(report)
        return reports

    def get_report(self, duplication: dict) -> Report:
        """ Parse a report from the given output file. """

        checker_name = 'jscpd'
        duplication_data_1 = duplication['firstFile']
        file_path_1 = duplication_data_1['name']
        if not os.path.exists(file_path_1):
            LOG.warning("Source file does not exist or cannot be found: %s. "
                        "If needed, use the -a flag when generating the "
                        "JSCPD report to include the absolute path.",
                        file_path_1)
        file_obj_1 = get_or_create_file(file_path_1, self._file_cache)

        duplication_data_2 = duplication['secondFile']
        file_path_2 = duplication_data_2['name']
        if not os.path.exists(file_path_2):
            LOG.warning("Source file does not exist or cannot be found: %s. "
                        "If needed, use the -a flag when generating the "
                        "JSCPD report to include the absolute path.",
                        file_path_2)
        file_obj_2 = get_or_create_file(file_path_2, self._file_cache)

        report = Report(
            file=file_obj_1,
            line=int(duplication_data_1['startLoc']['line']),
            column=int(duplication_data_1['startLoc']['column']),
            message=f"Duplicated code of {duplication['lines']} lines. "
                    f"Duplicates {file_path_2}, starting line"
                    f" {int(duplication_data_2['startLoc']['line'])}",
            checker_name=checker_name,
            category=checker_name,
            bug_path_events=[]
        )

        report.notes.append(BugPathEvent(
            file=file_obj_2,
            line=int(duplication_data_2['startLoc']['line']),
            column=int(duplication_data_2['startLoc']['column']),
            message=f"Duplicated code of {duplication['lines']} lines. "
                    f"Duplicates {file_path_1}, starting line "
                    f"{int(duplication_data_1['startLoc']['line'])}"
        ))

        return report

    def _parse_line(self, it: Iterator[str], line: str) -> Tuple[List[
            Report], str]:
        # FIXME: This method is a placeholder to allow instantiation of the
        #  Parser class.
        # The _parse_line method is required because Parser is an abstract
        # class that expects this method to be implemented in subclasses.
        return [], ""
